package com.lzw.data;

import com.lzw.app.Instance;
import com.lzw.utils.DateUtils;
import com.lzw.utils.LogUtils;

import java.io.Serializable;
import java.util.*;

/**
 * @author LZW
 */
public class AppRepository implements Serializable {
    public static final long serialVersionUID = 2020L;
    private Map<String, Map<String, Instance>> data = new HashMap<String, Map<String, Instance>>();

    public Map<String, Map<String, Instance>> getData() {
        return data;
    }

    public void setData(Map<String, Map<String, Instance>> data) {
        this.data = data;
    }

    /**
     * 注册实例(线程同步)
     *
     * @param instance
     */
    public synchronized void registerInstance(Instance instance) {
        String name = instance.getName();
        String id = instance.getId();
        Map<String, Instance> meta = new HashMap<String, Instance>(16);
        meta.put(id, instance);
        data.put(name, meta);
    }

    /**
     * 根据应用名称移除与之对应的所有注册实例
     *
     * @param name
     */
    public synchronized void removeByName(String name) {
        data.remove(name);
        StringBuilder sb = new StringBuilder();
        LogUtils.printLogRemoveByName(name,sb);
        System.out.println(sb);
    }

    /**
     * 根据应用名称+id移除与之对应的所有注册实例
     *
     * @param name
     */
    public synchronized void removeByIdAboutName(String name, String id) {
        Map<String, Instance> instanceMap = data.get(name);
        instanceMap.remove(id);
        StringBuilder sb = new StringBuilder();
        LogUtils.printLogRemoveById(id,sb);
        System.out.println(sb);
    }

    /**
     * 清理过期注册实例
     *
     * @return
     */
    public synchronized void cleatInstance() {
        int count = 0;
        List<String> names = getExpireNames();
        for (String name : names) {
            removeByName(name);
        }
        Map<String, String> expireIds = getExpireIds();
        for (String id : expireIds.keySet()) {
            String name = expireIds.get(id);
            removeByIdAboutName(name, id);
        }
    }


    /**
     * 获取过期实例的名称
     *
     * @return
     */
    private synchronized List<String> getExpireNames() {
        List<String> result = new ArrayList<String>();
        if (data != null && data.size() > 0) {
            //存在实例
            Set<String> names = data.keySet();
            for (String name : names) {
                Map<String, Instance> instanceMap = data.get(name);
                if (instanceMap == null || instanceMap.size() == 0) {
                    result.add(name);
                }
            }
        }
        return result;
    }

    /**
     * 获取过期实例的id
     *
     * @return
     */
    private synchronized Map<String, String> getExpireIds() {
        long now = System.currentTimeMillis();
        Map<String, String> result = new HashMap<String, String>(16);
        if (data != null && data.size() > 0) {
            //存在实例
            Set<String> names = data.keySet();
            for (String name : names) {
                Map<String, Instance> instanceMap = data.get(name);
                if (instanceMap != null && instanceMap.size() > 0) {
                    Set<String> ids = instanceMap.keySet();
                    for (String id : ids) {
                        Instance instance = instanceMap.get(id);
                        if (instance == null) {
                            result.put(id, name);
                            continue;
                        }
                        long lastPing = instance.getLastPing();
                        long sub = now - lastPing;
                        int invalidate = instance.getInvalidateSecond() * 1000;
                        if (sub > invalidate) {
                            result.put(id, name);
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 重置指定实例上一次的ping时刻
     *
     * @param instance
     */
    @SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
    public synchronized void resetLastPing(Instance instance) {
        String name = instance.getName();
        String id = instance.getId();
        Map<String, Instance> instanceMap = data.get(name);
        if (instanceMap != null) {
            Instance instanceData = instanceMap.get(id);
            long currentMillis = DateUtils.getNowTimeMillis();
            if(instanceData!=null) {
                instanceData.setLastPing(currentMillis);
            }
        }
    }
}
